#include <stdio.h>
#include <stdlib.h>

#include "distance.h"
#include "sort.h"
#include "timer.h"
#include "linkage.h"
#include "clhelper.h"

FILE *file;

// Helper function to generate some random data
float * dataGenerate (int N, int D) {
	float *dataMat = (float *)malloc(N * D * sizeof(float));
	srand(10);
	//printf("Generating Data (%i by %i) ...\n", D, N);
	for (int i = 1; i < N * D; i++) {
		dataMat[i] = (float)rand()/(float)RAND_MAX;
		//printf("%f ", dataMat[i]);
	}
	return dataMat;
}

void printGram(dendrite *gram, int N)
{
  printf("\n\n");
  for(int i = 0; i < N; i++)
    printf("%d\t%d\t%f\n", gram[i].i, gram[i].j, gram[i].distance);
  printf("\n\n");    
}

int compGram(dendrite *a, dendrite *b, int N) {
  int error = 0;
  for(int i = 0; i < N; i++)
    if(((a[i].i != b[i].i && a[i].j != b[i].i) || (a[i].i != b[i].j && a[i].j != b[i].j)) && a[i].distance != b[i].distance)
    {
      printf("Join: %d\t\t\tA: %d & %d - %f\t\t\tB: %d & %d - %f\n", i, a[i].i, a[i].j, a[i].distance, b[i].i, b[i].j, b[i].distance);
      error = 1;
    }
  
  return error;
}

int main (int argc, const char * argv[]) {
  getOpenCLInfo(); // Print out machine specs

	int N, D, n, d, i;
	int Nstart = 4096;
	int Dstart = 2;
	int numN = 4;
	int numD = 7;
	
	int numDataMat = 10;
	//int multiplier =512;
  
//  N = 8192;
//  D = 64;
//	float *data = dataGenerate(N, D);
//  runTests(N, D, 5, data);
	
	file = fopen("cpu.txt", "wt");
   
  
	float *data = NULL;
	float *distance = NULL;
	//dendrite *gram = NULL;
	//dendrite *comp = NULL;
	//int *assignment = NULL;
	double *elapsed = (double *)malloc(sizeof(double) * numDataMat);
	double elapsedsum = 0;
	double elapsedavg;
  double emax = FLT_MIN;
  double emin = FLT_MAX;
	
	fprintf(file, "\\begin{tabular}{ r | r | r } \n");
	fprintf(file, "\\hline \n");
	fprintf(file, "n & m & CPU time \\\\ \n");
	fprintf(file, "\\hline \n");
	for (d = 0; d < numD; d++)
		for (n = 0; n < numN; n++) {
			elapsedsum = 0;
			for (i = 0; i < numDataMat; i++)  {
				
				N = Nstart + Nstart * n;
				D = Dstart * (int)pow(2,d);
		
				if (data != NULL) free(data);
				data = dataGenerate(N, D);
		
				if (distance != NULL) free(distance);
				distance = (float *)malloc(sizeof(float) * N * (N - 1) / 2);
				
				startTimer();
				distance3(N, D, data, distance);
				elapsed[i] = stopTimer();
			}
      
      for(i = 0; i < numDataMat; i++)
      {
        if(elapsed[i] > emax)
          emax = elapsed[i];
        if(elapsed[i] < emin)
          emin = elapsed[i];
      }
      
      for(i = 0; i < numDataMat; i++)
        if(elapsed[i] != emax && elapsed[i] != emin)
          elapsedsum += elapsed[i];
        
			elapsedavg = elapsedsum / (numDataMat - 2);
			
			fprintf(file, "%i & %i & %2.3f \\\\ \n", N, D, elapsedavg);
			printf("%i & %i & %2.3f \\\\ \n", N, D, elapsedavg);
		}
		fprintf(file, "\\end{tabular}");
	
	fclose(file);
	
	
		//Generate an array of data matrices
	/**
	for (int i = 0; i < numDataMat; i++) {
		N = multiplier * (i + 1);
		D = multiplier * (numDataMat - i);
		    
		if (data != NULL) free(data);
		data = dataGenerate(N, D);
		
		if (distance != NULL) free(distance);
    distance = (float *)malloc(sizeof(float) * N * (N - 1) / 2);
		distance3(N, D, data, distance);
    
//    startTimer();
//    testCL_prune(N, distance);
//    double elapsed=stopTimer();
//		printf("\nElapsed time: %f\n\n",elapsed);   

 
    
    if (gram != NULL) free(gram);
    gram = (dendrite *)malloc(sizeof(dendrite) * (N - 1));
		startTimer();
		testCL_prune(N, distance);
		elapsed=stopTimer();
		printf("Fast elapsed time: %f\n\n",elapsed);
		startTimer();
		comp(N, distance, gram);
		elapsed=stopTimer();
		printf("Fast elapsed time: %f\n\n",elapsed);
    
//    //printGram(gram, N - 1);
//    
//		startTimer();
//    denSlow(N, D, distance, comp);
//		elapsed=stopTimer();
//		printf("Slow elapsed time: %f\n\n",elapsed);
//    
//    //printGram(comp, N - 1);
//    
//    if(compGram(gram, comp, N - 1) == 1)
//      printf("error\n");

    //if(assignment != NULL) free(assignment);
    //assignment = (int *)malloc(sizeof(int) * N);
    //assignLaunch(gram, 4, N, assignment);
    
    //for(int j = 0; j < N; j++)
    //  printf("%i ", assignment[j]);
    //printf("\n");
	} 
	**/
	
	free(distance);
	free(data);
  free(elapsed);
  //free(assignment);
  //free(gram);
	
   
	return 0;
}
